package org.yu.register.machine;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.RecipeWrapper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yu.api.util.ITickable;
import org.yu.register.CapabilityRegister;
import org.yu.register.MobEffectRegister;
import org.yu.register.RecipeRegister;
import org.yu.register.capability.LingQiStorage;
import org.yu.register.item.SilkBagSealed;

import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
public class ImpactAltarBlockEntity extends BlockEntity implements ITickable {
    private float renderAngle=0;
    int dealTime=0;
    protected final ItemStackHandler itemStackHandler=new ItemStackHandler(1){
        @Override
        protected void onContentsChanged(int slot) {
            ImpactAltarBlockEntity.this.setChanged();
            if(level!=null)
            level.sendBlockUpdated(getBlockPos(),getBlockState(),getBlockState(),3);
            dealTime=0;
        }
    };
    protected final RecipeWrapper wrapper=new RecipeWrapper(itemStackHandler);
    protected final LingQiStorage lingQiStorage=new LingQiStorage(666666);
    protected  AABB effectAABB;
    public ImpactAltarBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
        super(pType, pWorldPosition, pBlockState);
        effectAABB=new AABB(-10,-10,-10,10,10,10).move(pWorldPosition);
    }

    @NotNull
    @Override
    public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
            if(cap== CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
                return LazyOptional.of(()->itemStackHandler).cast();
            if(cap== CapabilityRegister.LING_QI_STORAGE)
                return LazyOptional.of(()->lingQiStorage).cast();
        return super.getCapability(cap, side);
    }

    public float getRenderAngle() {
        return renderAngle;
    }

    @Override
    public void tick() {
        if(level!=null) {
            if (level.isClientSide) {
                renderAngle += 0.25f;
                if (renderAngle >= 360) renderAngle = 0;
            }else {
                    var item = itemStackHandler.getStackInSlot(0);
                    if (item.getItem() instanceof SilkBagSealed&&!item.isEmpty()) {
                        if(dealTime>=60) {
                            dealTime=0;
                        item.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(iItemHandler -> {
                            effectEntity(item);
                        });
                    }else {
                            dealTime++;

                        }
                }
            }
        }
    }

    protected void effectEntity(ItemStack item) {
        if(level instanceof ServerLevel serverLevel){
            var recipe=serverLevel.getRecipeManager().getRecipeFor(RecipeRegister.impactRecipe.recipeType,wrapper,serverLevel);
          if(recipe.isPresent()&&recipe.get().result.equals("Awaken"))  {
                if (item.hurt(1, level.random, null)) {
                    itemStackHandler.setStackInSlot(0, ItemStack.EMPTY);
                }
                serverLevel.getEntities((Entity) null, effectAABB, this::shouldEffect)
                        .forEach(entity -> {
                            if(entity instanceof LivingEntity livingEntity&&livingEntity.hasEffect(MobEffectRegister.awakenEffect.get()))
                            livingEntity.getCapability(CapabilityRegister.LING_QI).ifPresent(lingQi -> {
                                lingQi.unlock();
                                livingEntity.removeEffect(MobEffectRegister.awakenEffect.get());
                                lingQiStorage.receive(100, false);
                                if(entity instanceof Player player){
                                    player.displayClientMessage(new TranslatableComponent("yu.message.PlayerAwaken"),false);
                                }
                            });
                        });
            }
        }
    }

    protected boolean shouldEffect(Entity entity) {
        return entity.getCapability(CapabilityRegister.LING_QI).isPresent();
    }

    @Override
    public AABB getRenderBoundingBox() {
        return INFINITE_EXTENT_AABB;
    }

    @Override
    public void load(CompoundTag pTag) {
        super.load(pTag);
        itemStackHandler.deserializeNBT(pTag.getCompound("Item"));
        if(pTag.contains("LingQi"))
            lingQiStorage.deserializeNBT(pTag.get("LingQi"));
    }

    @Override
    protected void saveAdditional(CompoundTag pTag) {
        super.saveAdditional(pTag);
        pTag.put("Item",itemStackHandler.serializeNBT());
        pTag.put("LingQi",lingQiStorage.serializeNBT());
    }

    @Nullable
    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);
    }

    @Override
    public void handleUpdateTag(CompoundTag pTag) {
        super.handleUpdateTag(pTag);
        itemStackHandler.deserializeNBT(pTag.getCompound("Item"));
        if(pTag.contains("LingQi"))
            lingQiStorage.deserializeNBT(pTag.get("LingQi"));
    }

    @NotNull
    @Override
    public CompoundTag getUpdateTag() {
        var pTag=super.getUpdateTag();
        pTag.put("Item",itemStackHandler.serializeNBT());
        pTag.put("LingQi",lingQiStorage.serializeNBT());
        return pTag;
    }

    @SuppressWarnings("all")
    @Override
    public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
        this.handleUpdateTag(pkt.getTag());
    }
}
